package client

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"ota-client/internal/config"
	"ota-client/internal/logger"
)

// OTAClient OTA客户端
type OTAClient struct {
	config     *config.Config
	httpClient *http.Client
}

// CheckResponse 检查更新响应
type CheckResponse struct {
	NeedUpdate     bool   `json:"need_update"`
	LatestVersion  string `json:"latest_version"`
	CurrentVersion string `json:"current_version"`
	Message        string `json:"message"`
	FirmwareInfo   struct {
		Version     string    `json:"version"`
		Description string    `json:"description"`
		FileSize    int64     `json:"file_size"`
		ReleaseTime time.Time `json:"release_time"`
		DownloadURL string    `json:"download_url"`
	} `json:"firmware_info"`
	TaskInfo struct {
		ID            string    `json:"id"`
		Name          string    `json:"name"`
		ExecuteTime   string    `json:"execute_time"`
		EffectiveTime time.Time `json:"effective_time"`
	} `json:"task_info"`
}

// NewOTAClient 创建OTA客户端
func NewOTAClient(cfg *config.Config) *OTAClient {
	return &OTAClient{
		config: cfg,
		httpClient: &http.Client{
			Timeout: time.Duration(cfg.Client.DownloadTimeout) * time.Second,
		},
	}
}

// CheckAndUpdate 检查并执行更新
func (c *OTAClient) CheckAndUpdate() {
	// 检查更新
	checkResp, err := c.checkUpdate()
	if err != nil {
		logger.Errorf("检查更新失败: %v", err)
		return
	}

	if !checkResp.NeedUpdate {
		logger.Info(checkResp.Message)
		return
	}

	logger.Infof("发现新版本: %s -> %s", checkResp.CurrentVersion, checkResp.LatestVersion)
	logger.Infof("固件描述: %s", checkResp.FirmwareInfo.Description)
	logger.Infof("文件大小: %d bytes", checkResp.FirmwareInfo.FileSize)

	// 创建临时目录
	if err := c.ensureTempDir(); err != nil {
		logger.Errorf("创建临时目录失败: %v", err)
		return
	}

	// 下载固件
	firmwarePath, err := c.downloadFirmware(checkResp.FirmwareInfo.DownloadURL)
	if err != nil {
		logger.Errorf("下载固件失败: %v", err)
		c.reportUpgradeStatus(checkResp.LatestVersion, "failed", fmt.Sprintf("下载失败: %v", err))
		return
	}

	// 验证签名
	if err := c.verifyFirmware(firmwarePath); err != nil {
		logger.Errorf("固件签名验证失败: %v", err)
		c.reportUpgradeStatus(checkResp.LatestVersion, "failed", fmt.Sprintf("签名验证失败: %v", err))
		return
	}

	logger.Info("固件下载和验证成功")

	// 模拟固件升级过程
	if err := c.simulateUpgrade(firmwarePath, checkResp.LatestVersion); err != nil {
		logger.Errorf("固件升级失败: %v", err)
		c.reportUpgradeStatus(checkResp.LatestVersion, "failed", fmt.Sprintf("升级失败: %v", err))
		return
	}

	// 报告升级成功
	c.reportUpgradeStatus(checkResp.LatestVersion, "success", "升级成功")
	logger.Infof("固件升级成功，当前版本: %s", checkResp.LatestVersion)

	// 更新配置中的版本号
	c.config.Device.Version = checkResp.LatestVersion
}

// checkUpdate 检查更新
func (c *OTAClient) checkUpdate() (*CheckResponse, error) {
	url := c.config.Server.URL + "/ota/check"

	requestData := map[string]string{
		"product_id":      c.config.Device.ProductID,
		"current_version": c.config.Device.Version,
		"sn":              c.config.Device.SN,
	}

	jsonData, err := json.Marshal(requestData)
	if err != nil {
		return nil, fmt.Errorf("序列化请求数据失败: %v", err)
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
	}

	req.Header.Set("Content-Type", "application/json")

	logger.Debugf("发送检查更新请求: %s", string(jsonData))

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("服务器返回错误: %d %s", resp.StatusCode, string(body))
	}

	var checkResp CheckResponse
	if err := json.NewDecoder(resp.Body).Decode(&checkResp); err != nil {
		return nil, fmt.Errorf("解析响应数据失败: %v", err)
	}

	return &checkResp, nil
}

// downloadFirmware 下载固件
func (c *OTAClient) downloadFirmware(downloadURL string) (string, error) {
	url := c.config.Server.URL + "/ota/download/" + downloadURL

	logger.Infof("开始下载固件: %s", url)

	resp, err := c.httpClient.Get(url)
	if err != nil {
		return "", fmt.Errorf("下载请求失败: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("下载失败，状态码: %d", resp.StatusCode)
	}

	// 创建本地文件
	filename := filepath.Base(downloadURL)
	if filename == "." || filename == "/" {
		filename = "firmware.bin"
	}

	localPath := filepath.Join(c.config.Client.TempDir, filename)

	file, err := os.Create(localPath)
	if err != nil {
		return "", fmt.Errorf("创建本地文件失败: %v", err)
	}
	defer file.Close()

	// 复制数据
	written, err := io.Copy(file, resp.Body)
	if err != nil {
		return "", fmt.Errorf("保存文件失败: %v", err)
	}

	logger.Infof("固件下载完成: %s (%d bytes)", localPath, written)
	return localPath, nil
}

// verifyFirmware 验证固件签名
func (c *OTAClient) verifyFirmware(firmwarePath string) error {
	// 读取固件文件
	firmwareData, err := os.ReadFile(firmwarePath)
	if err != nil {
		return fmt.Errorf("读取固件文件失败: %v", err)
	}

	// 下载签名文件
	signaturePath := firmwarePath + ".sum"
	if err := c.downloadSignature(firmwarePath, signaturePath); err != nil {
		return fmt.Errorf("下载签名文件失败: %v", err)
	}

	// 读取签名
	expectedSignature, err := os.ReadFile(signaturePath)
	if err != nil {
		return fmt.Errorf("读取签名文件失败: %v", err)
	}

	// 验证签名（假设使用HMAC-SHA256）
	actualSignature := c.calculateHMAC(firmwareData)
	expectedSig := strings.TrimSpace(string(expectedSignature))

	if actualSignature != expectedSig {
		return fmt.Errorf("签名验证失败: 期望 %s, 实际 %s", expectedSig, actualSignature)
	}

	logger.Info("固件签名验证成功")
	return nil
}

// downloadSignature 下载签名文件
func (c *OTAClient) downloadSignature(firmwarePath, signaturePath string) error {
	// 构建签名文件URL
	firmwareURL := filepath.Base(firmwarePath)
	signatureURL := firmwareURL + ".sum"

	// 从固件下载URL中提取产品ID部分
	parts := strings.Split(firmwareURL, "_")
	if len(parts) < 2 {
		return fmt.Errorf("无法从固件文件名解析产品ID")
	}
	productID := parts[0]

	url := c.config.Server.URL + "/ota/download/" + productID + "/" + signatureURL

	resp, err := c.httpClient.Get(url)
	if err != nil {
		return fmt.Errorf("下载签名请求失败: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("下载签名失败，状态码: %d", resp.StatusCode)
	}

	file, err := os.Create(signaturePath)
	if err != nil {
		return fmt.Errorf("创建签名文件失败: %v", err)
	}
	defer file.Close()

	_, err = io.Copy(file, resp.Body)
	if err != nil {
		return fmt.Errorf("保存签名文件失败: %v", err)
	}

	return nil
}

// calculateHMAC 计算HMAC签名
func (c *OTAClient) calculateHMAC(data []byte) string {
	// 这里使用SHA512 HMAC，与后端保持一致
	h := hmac.New(sha512.New, []byte(c.config.Device.Key))
	h.Write(data)
	return hex.EncodeToString(h.Sum(nil))
}

// simulateUpgrade 模拟固件升级过程
func (c *OTAClient) simulateUpgrade(firmwarePath, version string) error {
	logger.Info("开始固件升级...")

	// 模拟升级过程
	for i := 1; i <= 5; i++ {
		logger.Infof("升级进度: %d/5", i)
		time.Sleep(1 * time.Second)
	}

	logger.Info("固件升级完成")

	// 删除临时文件
	os.Remove(firmwarePath)
	os.Remove(firmwarePath + ".sum")

	return nil
}

// reportUpgradeStatus 报告升级状态
func (c *OTAClient) reportUpgradeStatus(version, status, message string) {
	url := c.config.Server.URL + "/ota/report"

	requestData := map[string]string{
		"sn":         c.config.Device.SN,
		"product_id": c.config.Device.ProductID,
		"version":    version,
		"status":     status,
		"message":    message,
	}

	jsonData, err := json.Marshal(requestData)
	if err != nil {
		logger.Errorf("序列化报告数据失败: %v", err)
		return
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		logger.Errorf("创建报告请求失败: %v", err)
		return
	}

	req.Header.Set("Content-Type", "application/json")

	logger.Debugf("发送升级状态报告: %s", string(jsonData))

	resp, err := c.httpClient.Do(req)
	if err != nil {
		logger.Errorf("发送报告请求失败: %v", err)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		logger.Errorf("报告状态失败: %d %s", resp.StatusCode, string(body))
		return
	}

	logger.Info("升级状态报告成功")
}

// ensureTempDir 确保临时目录存在
func (c *OTAClient) ensureTempDir() error {
	return os.MkdirAll(c.config.Client.TempDir, 0755)
}
